package ctd.util.converter.support;

import ctd.util.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;


public class MapToObject implements GenericConverter {
    private static final Logger LOGGER = LoggerFactory.getLogger(MapToObject.class);

    @SuppressWarnings("unchecked")
    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (sourceType.isMap()) {
            try {
                Object target = targetType.getType().newInstance();
                Map<String, Object> map = (Map<String, Object>) source;
                Set<String> keys = map.keySet();
                try {
                    BeanUtils.copy(map, target);

                    boolean hasProperty = true;
                    try {
                        target.getClass().getMethod("setProperty");
                    } catch (NoSuchMethodException e) {
                        hasProperty = false;
                    }
                    for (String key : keys) {
                        try {
                            target.getClass().getDeclaredField(key);
                        } catch (NoSuchFieldException e) {
                            if (hasProperty)
                                BeanUtils.setPropertyInMap(target, key, map.get(key));
                        }
                    }
                } catch (Exception e) {
                    LOGGER.error("this error does not affact the program run: " + e.getMessage());
                    for (String k : keys) {
                        try {
                            BeanUtils.setProperty(target, k, map.get(k));
                        } catch (Exception e1) {
                            try {
                                BeanUtils.setPropertyInMap(target, k, map.get(k));
                            } catch (Exception ignored) {
                            }
                        }
                    }
                }
                return target;
            } catch (Exception e) {
                throw new IllegalStateException("falied to convert map to bean", e);
            }
        } else {
            throw new IllegalStateException("source object must be a map");
        }
    }

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        Set<ConvertiblePair> set = new HashSet<ConvertiblePair>();
        set.add(new ConvertiblePair(Map.class, Object.class));
        return set;
    }

}
